from typing import Set, List, Tuple, Any

from common.equipment.interface import create_equip
from common.equipment.reference import Equipment
from common.resources import Resource
from gui.signals import SIGNALS
from utils.db import DBSession
from utils.reference import ValueRange, message_box_information


class Bag:
    __slots__ = (
        'coin',
        'material',
        'consumable',
        'equipment',
        'cap'
    )

    def __init__(self):
        self.coin = 1000
        self.cap = ValueRange(100, 0)
        self.material = dict()
        self.consumable = dict()
        self.equipment: Set[Equipment] = set()

    @property
    def title(self):
        return f'纳戒 ({self.cap})'

    def __json__(self):
        return {
            'coin': self.coin,
            'material': self.material,
            'consumable': self.consumable,
            'equipment': list(self.equipment),
        }

    def load(self, data: dict) -> None:
        self.coin = data['coin']
        self.material = data['material']
        self.consumable = data['consumable']

        for equip_meta in data['equipment']:
            if 'attrs' in equip_meta:
                equip_meta.update(equip_meta.pop('attrs'))

            e = create_equip(equip_meta.pop('key'), equip_meta, equip_meta['quality'])
            self.equipment.add(e)

        self.cap.current = len(self.equipment) + len(self.consumable) + len(self.material)

    def iter_materials(self):
        for material, quantity in self.material.items():
            r: Resource = DBSession.materials[material]
            yield r, quantity

    def iter_equipments(self):
        for equipment in self.equipment:
            yield equipment, 1

    def iter(self):
        yield from self.iter_equipments()
        yield from self.iter_materials()

    def check(self, data: List[Tuple[int, str, Any, int]]):
        use_cap = 0
        for opt, attr, key, num in data:
            # 加入物品
            if opt:
                if attr == 'equipment':
                    # 装备不可叠加 使用容量直接加一
                    use_cap += 1
                else:
                    # 其他资源可叠加
                    self_attr: dict = getattr(self, attr)
                    # 如果背包里不存在该物品
                    if key not in self_attr:
                        use_cap += 1
            # 移出物品
            else:
                if attr == 'equipment':
                    use_cap -= 1
                else:
                    self_attr: dict = getattr(self, attr)
                    # 存在, 且移出全部数量
                    if self_attr.get(key) == num:
                        use_cap -= 1

        return (self.cap.current + use_cap) <= self.cap.maximum, use_cap

    def update(self, data: List[Tuple[int, str, Any, int]]):
        check_status, use_cap = self.check(data)
        if not check_status:
            message_box_information('纳戒可用空间不足')
            return False

        for opt, attr, key, num in data:
            if opt:
                if attr == 'equipment':
                    self.equipment.add(key)
                else:
                    self_attr: dict = getattr(self, attr)
                    if key in self_attr:
                        self_attr[key] += num
                    else:
                        self_attr[key] = num
            else:
                if attr == 'equipment':
                    self.equipment.remove(key)
                else:
                    self_attr: dict = getattr(self, attr)
                    if key in self_attr:
                        self_attr[key] -= num
                        if self_attr[key] == 0:
                            del self_attr[key]

        self.cap.current += use_cap
        # 更新快捷栏的纳戒容量显示
        SIGNALS.change_quick_bar.emit()

        return True
